package comparisons

import (
	"jvm/instructions/base"
	"jvm/rtda"
)

// *****************************************************************
// 栈顶弹两个long型元素，第二个和第一个比大小 大, 等, 小 --> 1, 0, -1
type LCMP struct {
	base.NoOperandsInst
}

func (self *LCMP) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	if v1 > v2 {
		stack.PushInt(1)
	} else if v1 == v2 {
		stack.PushInt(0)
	} else {
		stack.PushInt(-1)
	}
}

// *****************************************************************
// fcmp通用函数
func fcmp(frame *rtda.Frame, gFlag bool) {
	stack := frame.OPStack()
	v2 := stack.PopFloat()
	v1 := stack.PopFloat()
	if v1 > v2 {
		stack.PushInt(1)
	} else if v1 == v2 {
		stack.PushInt(0)
	} else if v1 < v2 {
		stack.PushInt(-1)
	} else if gFlag {
		stack.PushInt(1)
	} else {
		stack.PushInt(-1)
	}
}

// *****************************************************************
type FCMPG struct {
	base.NoOperandsInst
}

func (self *FCMPG) Execute(frame *rtda.Frame) {
	fcmp(frame, true)
}

// *****************************************************************
type FCMPL struct {
	base.NoOperandsInst
}

func (self *FCMPL) Execute(frame *rtda.Frame) {
	fcmp(frame, false)
}

// *****************************************************************
// dcmp通用函数
func dcmp(frame *rtda.Frame, gFlag bool) {
	stack := frame.OPStack()
	v2 := stack.PopDouble()
	v1 := stack.PopDouble()
	if v1 > v2 {
		stack.PushInt(1)
	} else if v1 == v2 {
		stack.PushInt(0)
	} else if v1 < v2 {
		stack.PushInt(-1)
	} else if gFlag {
		stack.PushInt(1)
	} else {
		stack.PushInt(-1)
	}
}

// *****************************************************************
type DCMPG struct {
	base.NoOperandsInst
}

func (self *DCMPG) Execute(frame *rtda.Frame) {
	dcmp(frame, true)
}

// *****************************************************************
type DCMPL struct {
	base.NoOperandsInst
}

func (self *DCMPL) Execute(frame *rtda.Frame) {
	dcmp(frame, false)
}

// *****************************************************************
// 栈顶int型变量出栈，判断其是否==0 为真跳转，跳转地址为当前指令PC+offset
// offset为操作码后两字节(I2类型)
type IFEQ struct {
	base.BranchInst
}

func (self *IFEQ) Execute(frame *rtda.Frame) {
	i := frame.OPStack().PopInt()
	if i == 0 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IFNE struct {
	base.BranchInst
}

func (self *IFNE) Execute(frame *rtda.Frame) {
	i := frame.OPStack().PopInt()
	if i != 0 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IFLT struct {
	base.BranchInst
}

func (self *IFLT) Execute(frame *rtda.Frame) {
	i := frame.OPStack().PopInt()
	if i < 0 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IFLE struct {
	base.BranchInst
}

func (self *IFLE) Execute(frame *rtda.Frame) {
	i := frame.OPStack().PopInt()
	if i <= 0 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IFGT struct {
	base.BranchInst
}

func (self *IFGT) Execute(frame *rtda.Frame) {
	i := frame.OPStack().PopInt()
	if i > 0 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IFGE struct {
	base.BranchInst
}

func (self *IFGE) Execute(frame *rtda.Frame) {
	i := frame.OPStack().PopInt()
	if i >= 0 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
// 栈顶弹出两个int型变量，判断其是否相等 为真跳转，跳转地址为当前指令PC+offset
// offset为操作码后两字节(I2类型)
type IF_ICMPEQ struct {
	base.BranchInst
}

func (self *IF_ICMPEQ) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v1 == v2 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IF_ICMPNE struct {
	base.BranchInst
}

func (self *IF_ICMPNE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v1 != v2 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IF_ICMPGT struct {
	base.BranchInst
}

func (self *IF_ICMPGT) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v1 > v2 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IF_ICMPGE struct {
	base.BranchInst
}

func (self *IF_ICMPGE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v1 >= v2 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IF_ICMPLT struct {
	base.BranchInst
}

func (self *IF_ICMPLT) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v1 < v2 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IF_ICMPLE struct {
	base.BranchInst
}

func (self *IF_ICMPLE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v1 <= v2 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
// 栈顶弹出两个引用型变量，判断其是否相等 为真跳转，跳转地址为当前指令PC+offset
// offset为操作码后两字节(I2类型)
type IF_ACMPEQ struct {
	base.BranchInst
}

func (self *IF_ACMPEQ) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	r2 := stack.PopRef()
	r1 := stack.PopRef()
	if r1 == r2 {
		self.SetBranchPC(frame)
	}
}

// *****************************************************************
type IF_ACMPNE struct {
	base.BranchInst
}

func (self *IF_ACMPNE) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	r2 := stack.PopRef()
	r1 := stack.PopRef()
	if r1 != r2 {
		self.SetBranchPC(frame)
	}
}
